package com.ease.util.events {

import flash.events.Event;
import flash.events.IEventDispatcher;

import mx.core.FlexGlobals;
import mx.core.UIComponent;

/**
 * A queue based event dispatcher that queues the provided events until a dispatch is
 * explicitly requested. In the absence of an explicit dispatch request, the queued events
 * are dispatched on the next frame.
 */
public class QueuingEventDispatcher {
   private var _queue:Array/*Event*/ = [];

   /**
    * Initializes an instance of this class.
    *
    * @param target
    *    Value for the <code>target</code> property.
    * @param filterFunction
    *    An optional function to be called before dispatching each event. Useful to
    *    filter out events that are no longer valid in the client context.
    *    In form of:
    *    <code>function filter(event:Event):Boolean;</code>
    */
   public function QueuingEventDispatcher(
         target:IEventDispatcher = null,
         filterFunction:Function = null) {
      this.target = target;
      this.filterFunction = filterFunction;
   }

   /**
    * The target to use for dispatching the events submitted to this queue.
    */
   public var target:IEventDispatcher;

   /**
    * Optional function to call before dispatching each event. Useful to filter out
    * events that are no longer valid in the client context.
    *
    * <p>In form of:
    * <code>function filter(event:Event):Boolean;</code></p>
    *
    * <p>Returning <code>false</code> prevents dispatching the given event.</p>
    */
   public var filterFunction:Function;

   /**
    * Adds the provided event to the queue of events awaiting dispatch.
    */
   public function enqueue( event:Event ):void {
      if (event == null) {
         return;
      }
      if (_queue.length == 0) {
         scheduleDispatch();
      }
      _queue.push( event );
   }

   /**
    * Flushes the queued events by dispatching them on the <code>target</code>.
    */
   public function dispatchPendingEvents():void {
      var events:Array/*Event*/ = _queue;
      _queue = [];

      for each (var ev:Event in events) {
         // filter out the event based on the filterFunction return
         if ( this.filterFunction != null && !this.filterFunction( ev ) ) {
            continue;
         }

         this.target.dispatchEvent( ev );
      }
   }

   private function scheduleDispatch():void {
      var app:UIComponent = FlexGlobals.topLevelApplication as UIComponent;
      app.callLater( dispatchPendingEvents );
   }
} // class

}